/**
 * Calculon - A Java chess-engine.
 *
 * Copyright (C) 2008-2009 Barry Smith
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package nl.zoidberg.calculon.analyzer;

import java.util.HashSet;
import java.util.Set;

import nl.zoidberg.calculon.engine.BitBoard;
import nl.zoidberg.calculon.engine.MoveGenerator;
import nl.zoidberg.calculon.engine.BitBoard.BitBoardMove;
import nl.zoidberg.calculon.model.Game;
import nl.zoidberg.calculon.model.Piece;

public class GameScorer {
	public static final int MATE_SCORE = -100000;
	
	private static GameScorer instance = getUnweightedScorer();
	
	private static GameScorer getUnweightedScorer() {
		GameScorer rv = new GameScorer();
		
		rv.addScorer(new MaterialScorer());
		rv.addScorer(new BishopPairScorer());
		rv.addScorer(new BishopMobilityScorer());
		rv.addScorer(new PawnStructureScorer());
		rv.addScorer(new KnightScorer());
		rv.addScorer(new RookScorer());
		rv.addScorer(new KingSafetyScorer());
		
		return rv;
	}
	
	private Set<PositionScorer> scorers = new HashSet<PositionScorer>();
	
	public static GameScorer getDefaultScorer() {
		return instance;
	}
	
	public void addScorer(PositionScorer scorer) {
		scorers.add(scorer);
	}
	
	/**
	 * Generate a score - positive is good for the current player. Position scorers however can stick with the 
	 * convention of having white as positive.
	 * 
	 * @param board
	 * @param quiesce Indicates whether quiescence searching should be applied.
	 * @return
	 */
	public int score(BitBoard bitBoard, boolean quiesce, int alpha, int beta) {

//		System.out.println("score(" + alpha + ","+beta+")");
		String result = bitBoard.getResult();
		
		if(result == Game.RES_DRAW) {
			return 0;
		}
		
		if(result == Game.RES_BLACK_WIN || result == Game.RES_WHITE_WIN) {
			return MATE_SCORE;
		}
		
		if(quiesce) {
			return quiesce(bitBoard, alpha, beta, 0);
		}
		
		int score = 0;
		
		for(PositionScorer scorer: scorers) {
			score += scorer.scorePosition(bitBoard);
		}

		return score * (bitBoard.getPlayer() == Piece.WHITE ? 1 : -1);
	}
	
	public int quiesce(BitBoard bitBoard, int alpha, int beta, int depth) {
	    int standPat = this.score(bitBoard, false, alpha, beta);
//	    if(true) return standPat;
	    
	    if(standPat >= beta) {
	        return beta;
	    }
	    
	    if(alpha < standPat) {
	        alpha = standPat;
	    }
	    
	    if(depth >= 0) {
	    	return alpha;
	    }
	 
	    for(BitBoardMove move: new MoveGenerator(bitBoard).getThreateningMoves()) {
	    	System.out.println("Q:" + move.getAlgebraic());
	    	bitBoard.makeMove(move);
	        int score = -quiesce(bitBoard, -beta, -alpha, depth++);
	    	bitBoard.unmakeMove();
	 
	        if( score >= beta) {
	            return beta;
	        }
	        if( score > alpha) {
	           alpha = score;
	        }
	    }
	    
	    return alpha;
	}	
}
